import 'dart:convert';
import 'dart:io';
import 'dart:math';

import 'package:crypto/crypto.dart';
import 'package:dio/dio.dart';
import "package:dio/src/response.dart" as DioResponse;
import 'package:get/get.dart';
import 'package:largefriends/config/lf_config.dart';
import 'package:largefriends/net/lf_api_url.dart';
import 'package:largefriends/net/lf_dio_util.dart';
import 'package:largefriends/utils/lf_dialog_utils.dart';
import 'package:largefriends/utils/lf_logger.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
import 'package:uuid/uuid.dart';

import '../entity/entities/lf_token_entity.dart';
import '../service/manager/lf_store_helper.dart';
import '../pages/lf_suspend/lf_suspend_logic.dart';
import '../service/lf_auth_service.dart';
import '../utils/lf_devices_utils.dart';
import '../widgets/dialog_action_tip.dart';
import 'error_handle.dart';

class LfTokenInterceptor extends Interceptor {
  static const String _headerToken = "Token";
  static const String _headerDeviceToken = "devicetoken";
  static const String _headerClientVersion = "clientversion";
  static const String _headerSignature = "Signature";
  static const String _headerTimestamp = "Timestamp";
  static const String _headerNonce = "nonce";
  static const String _headerUuid = "UUID";
  static const String _headerDeviceType = "devicetype";

  LfAuthService authService = Get.find();
  Dio? _tokenDio;

  Future<String> _getToken() async {
    final Map<String, String> params = <String, String>{};
    var nowToken = authService.tokenEntity?.accessToken;
    if (nowToken != null && nowToken.isNotEmpty) {
      params["grant_type"] = "refresh_token";
      params["refresh_token"] = nowToken;
    }

    try {
      _tokenDio ??= Dio();
      if (appOpenLog) {
        _tokenDio!.interceptors.add(PrettyDioLogger(
            requestHeader: true,
            requestBody: true,
            responseBody: true,
            responseHeader: false,
            error: true,
            compact: true,
            maxWidth: 300));
      }
      _tokenDio!.options = LfDio().dio.options;
      _tokenDio!.options.headers
          .addAll(await _getHeaderMap(isRequestToken: true));
      final response =
          await _tokenDio!.post<dynamic>(apiAccessToken, data: params);
      //  lfLogger.w("Token code-${response.statusCode}");
      if (response.statusCode == ExceptionHandle.success) {
        var jsonData = json.decode(response.data);
        LfTokenEntity newTokenEntity = LfTokenEntity.fromJson(jsonData);
        authService.tokenEntity = newTokenEntity;
        authService.setToken(newTokenEntity);
        return newTokenEntity.accessToken!;
      }
    } catch (e) {
      lfLogger.e('刷新Token失败！${e.toString()}');
    }
    return "";
  }

  @override
  Future<void> onRequest(
      RequestOptions options, RequestInterceptorHandler handler) async {
    options.headers.addAll(await _getHeaderMap());
    super.onRequest(options, handler);
  }

  @override
  Future<void> onResponse(
      DioResponse.Response response, ResponseInterceptorHandler handler) async {
    var jsonData = json.decode(response.data);
    var code = jsonData["code"] ?? 0;
    if (code == codeTokenInvalid ||
        code == codeErrorLoginFirst2 ||
        code == codeLoginFirst ||
        code == codeSignError ||
        code == codeSignError2 ||
        code == codeTokenError ||
        code == codeAuthorizationExpired) {
      // DioUtils.instance.dio.c
      hideDialog();
      if (Get.isDialogOpen == false && !showTokenSheet) {
        showTokenSheet = true;
        await showActionTips(
            tips:
                "To protect your account, we'll log you out when you're away for a while. Please log in again.",
            actionButtonTip: "Log in",
            action: () {
              LfAuthService authService = Get.find();
              showTokenSheet = false;
              authService.loginOut();
            },
            dismissible: false,
            showCancel: false);
      }
    } else if (code == 30001055) {
      showTokenSheet = false;
      authService.loginOut(jumpSplash: false);
      toSuspendPage();
    }
    super.onResponse(response, handler);
  }

  Future<Map<String, dynamic>> _getHeaderMap(
      {bool isRequestToken = false}) async {
    Map<String, dynamic> headerMap = {};

    String clientVersion = await DevicesUtils.getVersion();
    headerMap.putIfAbsent(_headerClientVersion, () => clientVersion);

    headerMap[_headerUuid] = await _getUUID();

    int currentTimeStamp = (DateTime.now().millisecondsSinceEpoch) ~/ 1000;
    headerMap[_headerTimestamp] = currentTimeStamp;

    String nonce = _randomBit(4);
    headerMap[_headerNonce] = nonce;

    String appId = apiKey;
    String signature =
        _getSignature(appId: appId, time: currentTimeStamp, nonce: nonce);
    headerMap[_headerSignature] = signature;

    String deviceType = "1";
    if (Platform.isAndroid) {
      deviceType = "2";
    } else {
      deviceType = "1";
    }
    headerMap.putIfAbsent(_headerDeviceType, () => deviceType);

    var fireBaseToken = LfStorageManager.getString("firebase_token");

    ///在Main.dart 生成
    if (fireBaseToken != null && fireBaseToken.isNotEmpty) {
      headerMap[_headerDeviceToken] = fireBaseToken;
    }
    if (authService.tokenEntity?.accessToken == null &&
        isRequestToken == false) {
      await _getToken(); // 获取新的
    }
    String? token = authService.tokenEntity?.accessToken;
    headerMap.putIfAbsent(_headerToken, () => token ?? "");

    if (isRequestToken) {
      headerMap["AppId"] = appId;
      headerMap[_headerSignature] = _getSignKey(
          appId: appId,
          appSecret: apiSecret,
          time: currentTimeStamp,
          nonce: nonce);
    }
    return headerMap;
  }

  String _randomBit(int len) {
    String scopeF = "123456789"; //首位
    String scopeC = "0123456789"; //中间
    String result = "";
    for (int i = 0; i < len; i++) {
      if (i == 0) {
        result = scopeF[Random().nextInt(scopeF.length)];
      } else {
        result = result + scopeC[Random().nextInt(scopeC.length)];
      }
    }
    return result;
  }

  String _getSignKey(
      {required String appId,
      required String appSecret,
      required int time,
      required String nonce}) {
    var bytes = utf8.encode("$time$appId$appSecret$nonce");
    var digest = md5.convert(bytes);

    return digest.toString();
  }

  String _getSignature({String appId = "", int time = 0, String nonce = ""}) {
    var bytes = utf8.encode("$time$appId$nonce");
    var digest = md5.convert(bytes);

    return digest.toString();
  }

  Future<String> _getUUID() async {
    var uuid = LfStorageManager.getString("UUID");
    if (uuid != null && uuid.isNotEmpty) {
      return uuid;
    }
    uuid = const Uuid().v4();

    // final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
    // if (Platform.isAndroid) {
    //   var build = await deviceInfoPlugin.androidInfo;
    //   uuid = build.androidId ?? ""; //UUID for Android
    // } else if (Platform.isIOS) {
    //   var data = await deviceInfoPlugin.iosInfo;
    //   uuid = data.identifierForVendor ?? ""; //UUID for iOS
    // }
    LfStorageManager.putString("UUID", uuid);
    return uuid;
  }

  bool showTokenSheet = false;
}
